﻿using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Xml;
using EnvDTE;
using EnvDTE80;
using VSIXUtilities.DataObjects;
using System.Linq;
using CodeDocumentationSynchronizer.CodDocSync.Helpers;
using System.Windows.Media;
using Microsoft.VisualStudio.Language.Intellisense;
using Microsoft.VisualStudio.Labs;

namespace VSIXUtilities.Helpers.Extensions
{
    public static class CodeElementExtensions
    {
        public static string GetFriendlyName(this CodeElement CodeElementInsance)
        {
            if (CodeElementInsance.Kind == vsCMElement.vsCMElementImportStmt)
            {
                return ((CodeImport)CodeElementInsance).Namespace;
            }
            return CodeElementInsance.Name;
        }

        private static string GetDocCommentCore(this CodeElement CodeElementInstance, string Extension)
        {
            string stringXml = string.Empty;
            switch (CodeElementInstance.Kind)
            {
                case vsCMElement.vsCMElementClass:
                    stringXml = ((CodeClass2)CodeElementInstance).DocComment;
                    break;
                case vsCMElement.vsCMElementDelegate:
                    stringXml = ((CodeDelegate)CodeElementInstance).DocComment;
                    break;
                case vsCMElement.vsCMElementEnum:
                    stringXml = ((CodeEnum)CodeElementInstance).DocComment;
                    break;
                case vsCMElement.vsCMElementEvent:
                    stringXml = ((CodeEvent)CodeElementInstance).DocComment;
                    break;
                case vsCMElement.vsCMElementFunction:
                    stringXml = ((CodeFunction)CodeElementInstance).DocComment;
                    break;
                case vsCMElement.vsCMElementInterface:
                    stringXml = ((CodeInterface)CodeElementInstance).DocComment;
                    break;
                case vsCMElement.vsCMElementNamespace:
                    stringXml = ((CodeNamespace)CodeElementInstance).DocComment;
                    break;
                case vsCMElement.vsCMElementParameter:
                    stringXml = ((CodeParameter)CodeElementInstance).DocComment;
                    break;
                case vsCMElement.vsCMElementProperty:
                    stringXml = ((CodeProperty)CodeElementInstance).DocComment;
                    break;
                case vsCMElement.vsCMElementStruct:
                    stringXml = ((CodeStruct)CodeElementInstance).DocComment;
                    break;
                case vsCMElement.vsCMElementTypeDef:
                    stringXml = ((CodeType)CodeElementInstance).DocComment;
                    break;
                case vsCMElement.vsCMElementVariable:
                    stringXml = ((CodeVariable)CodeElementInstance).DocComment;
                    break;
                default:
                    stringXml = string.Empty;
                    break;
            }
            LanguageSpecifications LanguageSpecificationsInstance = Cache.LanguageSpecs[Extension];
            if (stringXml == string.Empty || stringXml.RemoveLineBreaks() == LanguageSpecificationsInstance.EmptyDocumentationString)
            {
                stringXml = CodeElementInstance.ParseDocCommentCore(LanguageSpecificationsInstance);
            }
            return stringXml.Replace(Environment.NewLine + " ", Environment.NewLine);
        }

        public static XmlDocument GetDocComment(this CodeElement CodeElementInstance, string Extension)
        {
            string stringXml = GetDocCommentCore(CodeElementInstance, Extension);
            LanguageSpecifications LanguageSpecificationsInstance = Cache.LanguageSpecs[Extension];
            if (LanguageSpecificationsInstance.StartTag.Length == 0)
            {
                stringXml = "<doc>" + stringXml + "</doc>";
            }
            XmlDocument XmlDocumentResult = new XmlDocument();
            XmlDocumentResult.LoadXml(stringXml);
            return XmlDocumentResult;
        }

        public static string ParseDocCommentCore(this CodeElement CodeElementInstance, LanguageSpecifications LanguageSpecificationsInstance)
        {
            TextPoint TextPointHeaderEnd = CodeElementInstance.GetStartPoint(vsCMPart.vsCMPartNavigate);
            if (TextPointHeaderEnd.Line > CodeElementInstance.StartPoint.Line)
            {
                string[] stringsRealDocComments = CodeElementInstance.StartPoint.CreateEditPoint().GetLines(CodeElementInstance.StartPoint.Line, TextPointHeaderEnd.Line).ToLines().Where(line => line.TrimStart().StartsWith(LanguageSpecificationsInstance.DocumentationNotation)).Select(Line => Line.TrimStart().Replace(LanguageSpecificationsInstance.DocumentationNotation, "")).ToArray();
                return LanguageSpecificationsInstance.StartTag + String.Join(Environment.NewLine, stringsRealDocComments).Trim() + LanguageSpecificationsInstance.EndTag;
            }
            else
            {
                return LanguageSpecificationsInstance.EmptyDocumentationString;
            }
        }

        public static void SetDocCommentCore(this CodeElement CodeElementInstance, string DocComment)
        {
            switch (CodeElementInstance.Kind)
            {
                case vsCMElement.vsCMElementClass:
                    ((CodeClass)CodeElementInstance).DocComment = DocComment;
                    break;
                case vsCMElement.vsCMElementDelegate:
                    ((CodeDelegate)CodeElementInstance).DocComment = DocComment;
                    break;
                case vsCMElement.vsCMElementEnum:
                    ((CodeEnum)CodeElementInstance).DocComment = DocComment;
                    break;
                case vsCMElement.vsCMElementEvent:
                    ((CodeEvent)CodeElementInstance).DocComment = DocComment;
                    break;
                case vsCMElement.vsCMElementFunction:
                    ((CodeFunction)CodeElementInstance).DocComment = DocComment;
                    break;
                case vsCMElement.vsCMElementInterface:
                    ((CodeInterface)CodeElementInstance).DocComment = DocComment;
                    break;
                case vsCMElement.vsCMElementParameter:
                    ((CodeParameter)CodeElementInstance).DocComment = DocComment;
                    break;
                case vsCMElement.vsCMElementProperty:
                    ((CodeProperty)CodeElementInstance).DocComment = DocComment;
                    break;
                case vsCMElement.vsCMElementStruct:
                    ((CodeStruct)CodeElementInstance).DocComment = DocComment;
                    break;
                case vsCMElement.vsCMElementTypeDef:
                    ((CodeType)CodeElementInstance).DocComment = DocComment;
                    break;
                case vsCMElement.vsCMElementVariable:
                    ((CodeVariable)CodeElementInstance).DocComment = DocComment;
                    break;
            }
        }

        public static void SetDocComment(this CodeElement CodeElementInstance, string Extension, string DocComment)
        {
            LanguageSpecifications LanguageSpecificationsInstance = Cache.LanguageSpecs[Extension];
            try
            {
                CodeElementInstance.DTE.UndoContext.Open("Insert Doc Comments");
                CodeElementInstance.RemoveDocComment(LanguageSpecificationsInstance);
                TextPoint startPoint = CodeElementInstance.StartPoint;
                EditPoint editPoint = startPoint.CreateEditPoint();
                string stringPadding = Environment.NewLine + string.Empty.PadLeft(startPoint.LineCharOffset - 1);
                editPoint.MoveToPoint(startPoint);
                foreach (string stringLine in DocComment.ToLines())
                {
                    editPoint.Insert(LanguageSpecificationsInstance.DocumentationNotation + stringLine + stringPadding);
                }
            }
            finally
            {
                CodeElementInstance.DTE.UndoContext.Close();
            }
        }

        public static void RemoveDocComment(this CodeElement CodeElementInstance, LanguageSpecifications LanguageSpecificationsInstance)
        {
            //The following line to fix vb bug when trying to set the "DocComment" of the CodeElement with an empty vlaue, visual studio inserts line break. The solution is to insert any comment then remove it manually.
            CodeElementInstance.SetDocCommentCore(LanguageSpecificationsInstance.GetRawDocumentation("ToBeDeleted"));
            TextPoint TextPointStart = CodeElementInstance.StartPoint;
            TextPoint TextPointEnd = CodeElementInstance.GetStartPoint(vsCMPart.vsCMPartNavigate);
            EditPoint editPoint = TextPointStart.CreateEditPoint();
            if (editPoint.Line > 1)
            {
                editPoint.MoveToLineAndOffset(editPoint.Line - 1, 1);
            }
            while (editPoint.Line < TextPointEnd.Line)
            {
                if (editPoint.GetLines(editPoint.Line, editPoint.Line + 1).TrimStart().StartsWith(LanguageSpecificationsInstance.DocumentationNotation))
                {
                    editPoint.DeleteLine();
                }
                else
                {
                    editPoint.MoveToLineAndOffset(editPoint.Line + 1, 1);
                }
            }
        }

        public static bool CanBeDocCommented(this CodeElement CodeElementInstance)
        {
            switch (CodeElementInstance.Kind)
            {
                case vsCMElement.vsCMElementClass:
                    return true;
                case vsCMElement.vsCMElementDeclareDecl:
                    return true;
                case vsCMElement.vsCMElementDelegate:
                    return true;
                case vsCMElement.vsCMElementEnum:
                    return true;
                case vsCMElement.vsCMElementEvent:
                    return true;
                case vsCMElement.vsCMElementEventsDeclaration:
                    return true;
                case vsCMElement.vsCMElementFunction:
                    return ((CodeFunction)CodeElementInstance).FunctionKind.HasFlag(vsCMFunction.vsCMFunctionFunction) || ((CodeFunction)CodeElementInstance).FunctionKind.HasFlag(vsCMFunction.vsCMFunctionConstructor);
                case vsCMElement.vsCMElementIDLCoClass:
                    return true;
                //case vsCMElement.vsCMElementIDLImport:
                //    return true;
                //case vsCMElement.vsCMElementIDLImportLib:
                //    return true;
                case vsCMElement.vsCMElementIDLLibrary:
                    return true;
                case vsCMElement.vsCMElementInterface:
                    return true;
                case vsCMElement.vsCMElementMacro:
                    return true;
                case vsCMElement.vsCMElementMap:
                    return true;
                //case vsCMElement.vsCMElementMapEntry:
                //    return true;
                case vsCMElement.vsCMElementModule:
                    return true;
                //case vsCMElement.vsCMElementOther:
                //    return true;
                //case vsCMElement.vsCMElementParameter:
                //    return true;
                case vsCMElement.vsCMElementProperty:
                    return true;
                case vsCMElement.vsCMElementStruct:
                    return true;
                case vsCMElement.vsCMElementTypeDef:
                    return true;
                case vsCMElement.vsCMElementUDTDecl:
                    return true;
                //case vsCMElement.vsCMElementUnion:
                //    return true;
                case vsCMElement.vsCMElementVBAttributeGroup:
                    return true;
                case vsCMElement.vsCMElementVCBase:
                    return true;
                case vsCMElement.vsCMElementVariable:
                    return true;
                default:
                    return false;
            }
        }

        public static bool IsParametersProvider(this CodeElement CodeElementInstance)
        {
            switch (CodeElementInstance.Kind)
            {
                case vsCMElement.vsCMElementDelegate:
                case vsCMElement.vsCMElementFunction:
                case vsCMElement.vsCMElementProperty:
                    return true;
                default:
                    return false;
            }
        }

        public static bool IsExtensionMethod(this CodeFunction CodeFunctionInstance)
        {
            if (!CodeFunctionInstance.IsShared || !CodeFunctionInstance.FunctionKind.HasFlag(vsCMFunction.vsCMFunctionFunction) || CodeFunctionInstance.Parent == null || !(CodeFunctionInstance.Parent is CodeClass2) || !((CodeClass2)CodeFunctionInstance.Parent).IsShared)
            {
                return false;
            }
            TextPoint TextPointStart = CodeFunctionInstance.GetStartPoint(vsCMPart.vsCMPartWholeWithAttributes);
            TextPoint TextPointEnd = CodeFunctionInstance.GetStartPoint(vsCMPart.vsCMPartNavigate);
            //string stringHeader = string.Concat(TextPointStart.CreateEditPoint().GetLines(TextPointStart.Line, TextPointEnd.Line).ToLines().Where(line => !line.TrimStart().StartsWith("'")));
            string stringHeader = string.Join(Environment.NewLine, TextPointStart.CreateEditPoint().GetLines(TextPointStart.Line, TextPointEnd.Line).ToLines().Where(line => !line.TrimStart().StartsWith("'")));
#warning the regex in CodeElementExtensions.IsExtensionMethod may not operate properly if there are commented keywords (like "this" and "Extension") in the same line of function declaration
            if (Regex.IsMatch(stringHeader, @"[(]\s*(?:(?:/\*(\S|\s)*\*/\s*)|(?://.*\s*))*\s*this", RegexOptions.Compiled))
            {
                return true;
            }
            if (Regex.IsMatch(stringHeader, @"<\s*Extension\s*[(]\s*[)]\s*>", RegexOptions.Compiled))
            {
                return true;
            }
            return false;
        }

        public static bool HasGenericArguments(this CodeElement CodeElementInstance)
        {
            switch (CodeElementInstance.Kind)
            {
                case vsCMElement.vsCMElementClass:
                    return ((CodeClass2)CodeElementInstance).IsGeneric;
                case vsCMElement.vsCMElementDelegate:
                    return ((CodeDelegate2)CodeElementInstance).IsGeneric;
                case vsCMElement.vsCMElementFunction:
                    return ((CodeFunction2)CodeElementInstance).IsGeneric;
                case vsCMElement.vsCMElementInterface:
                    return ((CodeInterface2)CodeElementInstance).IsGeneric;
                case vsCMElement.vsCMElementProperty:
                    return ((CodeProperty2)CodeElementInstance).IsGeneric;
                case vsCMElement.vsCMElementStruct:
                    return ((CodeStruct2)CodeElementInstance).IsGeneric;
                case vsCMElement.vsCMElementVariable:
                    return ((CodeVariable2)CodeElementInstance).IsGeneric;
                default:
                    return false;
            }
        }

        public static CodeElements GetParameters(this CodeElement CodeElementInstance)
        {
            switch (CodeElementInstance.Kind)
            {
                case vsCMElement.vsCMElementDelegate:
                    return ((CodeDelegate)CodeElementInstance).Parameters;
                case vsCMElement.vsCMElementFunction:
                    return ((CodeFunction)CodeElementInstance).Parameters;
                case vsCMElement.vsCMElementProperty:
                    return ((CodeProperty2)CodeElementInstance).Parameters;
                default:
                    return null;
            }
        }

        public static string[] GetTypeParameters(this CodeElement CodeElementInstance)
        {
#warning "Extensions.GetTypeParameters" needs to be adopted to other languages beside C#.
            List<string> Result = new List<string>();
            foreach (Match MatchInstance in new Regex(@"([<][ ]*|[ ]*[,][ ]*)(?<TypeParam>\w+)", RegexOptions.Compiled).Matches(CodeElementInstance.FullName.Split('.').Last()))
            {
                Result.Add(MatchInstance.Groups["TypeParam"].Value);
            }
            return Result.ToArray();
        }

        public static bool CanHaveDoumentableChildren(this CodeElement CodeElementInstance)
        {
#warning "Extensions.CanHaveDoumentableChildren" Needs to be reviewed.
            switch (CodeElementInstance.Kind)
            {
                //case vsCMElement.vsCMElementAttribute:
                //    return true;
                case vsCMElement.vsCMElementClass:
                    return true;
                //case vsCMElement.vsCMElementDeclareDecl:
                //    return true;
                //case vsCMElement.vsCMElementDelegate:
                //    return true;
                case vsCMElement.vsCMElementEnum:
                    return true;
                //case vsCMElement.vsCMElementIDLCoClass:
                //    return true;
                //case vsCMElement.vsCMElementIDLImport:
                //    return true;
                //case vsCMElement.vsCMElementIDLImportLib:
                //    return true;
                case vsCMElement.vsCMElementIDLLibrary:
                    return true;
                case vsCMElement.vsCMElementInterface:
                    return true;
                //case vsCMElement.vsCMElementMacro:
                //    return true;
                case vsCMElement.vsCMElementMap:
                    return true;
                //case vsCMElement.vsCMElementMapEntry:
                //    return true;
                case vsCMElement.vsCMElementModule:
                    return true;
                case vsCMElement.vsCMElementNamespace:
                    return true;
                case vsCMElement.vsCMElementOther:
                    return true;
                case vsCMElement.vsCMElementStruct:
                    return true;
                //case vsCMElement.vsCMElementTypeDef:
                //    return true;
                case vsCMElement.vsCMElementUDTDecl:
                    return true;
                //case vsCMElement.vsCMElementUnion:
                //    return true;
                //case vsCMElement.vsCMElementVBAttributeGroup:
                //    return true;
                //case vsCMElement.vsCMElementVCBase:
                //    return true;
                //case vsCMElement.vsCMElementVariable:
                //    return true;
                default:
                    return false;
            }

        }

        public static bool HasReturnValue(this CodeElement CodeElementInstance)
        {
            switch (CodeElementInstance.Kind)
            {
                case vsCMElement.vsCMElementDelegate:
                    switch (((CodeDelegate)CodeElementInstance).Type.TypeKind)
                    {
                        case vsCMTypeRef.vsCMTypeRefVoid:
                            return false;
                        default:
                            return true;
                    }
                case vsCMElement.vsCMElementFunction:
                    switch (((CodeFunction)CodeElementInstance).Type.TypeKind)
                    {
                        case vsCMTypeRef.vsCMTypeRefVoid:
                            return false;
                        default:
                            return true;
                    }
                case vsCMElement.vsCMElementProperty:
                    switch (((CodeProperty2)CodeElementInstance).Parameters.Count)
                    {
                        case 0:
                            return false;
                        default:
                            return true;            //an indexer
                    }
                default:
                    return false;
            }
        }

        public static vsCMAccess GetAccess(this CodeElement CodeElementInstance)
        {
            switch (CodeElementInstance.Kind)
            {
                case vsCMElement.vsCMElementClass:
                    return ((CodeClass)CodeElementInstance).Access;
                case vsCMElement.vsCMElementEnum:
                    return ((CodeEnum)CodeElementInstance).Access;
                case vsCMElement.vsCMElementFunction:
                    return ((CodeFunction)CodeElementInstance).Access;
                case vsCMElement.vsCMElementInterface:
                    return ((CodeInterface)CodeElementInstance).Access;
                case vsCMElement.vsCMElementStruct:
                    return ((CodeStruct)CodeElementInstance).Access;
                case vsCMElement.vsCMElementVariable:
                    return ((CodeVariable)CodeElementInstance).Access;
                case vsCMElement.vsCMElementDelegate:
                    return ((CodeDelegate)CodeElementInstance).Access;
                case vsCMElement.vsCMElementProperty:
                    return ((CodeProperty)CodeElementInstance).Access;
                case vsCMElement.vsCMElementEvent:
                    return ((CodeEvent)CodeElementInstance).Access;
                default:
                    return vsCMAccess.vsCMAccessDefault;
            }
        }

        public static StandardGlyphGroup GetGlyphGroup(this CodeElement CodeElementInstance)
        {
            switch (CodeElementInstance.Kind)
            {
                //case vsCMElement.vsCMElementAssignmentStmt:
                //    break;
                //case vsCMElement.vsCMElementAttribute:
                //    break;
                case vsCMElement.vsCMElementClass:
                    return StandardGlyphGroup.GlyphGroupClass;
                //case vsCMElement.vsCMElementDeclareDecl:
                //    break;
                //case vsCMElement.vsCMElementDefineStmt:
                //    break;
                case vsCMElement.vsCMElementDelegate:
                    return StandardGlyphGroup.GlyphGroupDelegate;
                case vsCMElement.vsCMElementEnum:
                    return StandardGlyphGroup.GlyphGroupEnum;
                case vsCMElement.vsCMElementEvent:
                    return StandardGlyphGroup.GlyphGroupEvent;
                case vsCMElement.vsCMElementEventsDeclaration:
                    return StandardGlyphGroup.GlyphGroupEvent;//
                case vsCMElement.vsCMElementFunction:
                    vsCMFunction FunctionType = ((CodeFunction)CodeElementInstance).FunctionKind;
                    if (FunctionType.HasFlag(vsCMFunction.vsCMFunctionConstructor))
                    {
                        return StandardGlyphGroup.GlyphGroupJSharpInterface;
                    }
                    else if (FunctionType.HasFlag(vsCMFunction.vsCMFunctionDestructor))
                    {
                        return StandardGlyphGroup.GlyphGroupJSharpMethod;
                    }
                    else if (FunctionType.HasFlag(vsCMFunction.vsCMFunctionOperator))
                    {
                        return StandardGlyphGroup.GlyphGroupOperator;
                    }
                    else if (((CodeFunction)CodeElementInstance).IsExtensionMethod())
                    {
                        switch (CodeElementInstance.GetAccess())
                        {
                            case vsCMAccess.vsCMAccessAssemblyOrFamily:
                                return StandardGlyphGroup.GlyphExtensionMethodFriend;
                            //case vsCMAccess.vsCMAccessDefault:
                            //    break;
                            case vsCMAccess.vsCMAccessPrivate:
                                return StandardGlyphGroup.GlyphExtensionMethodPrivate;
                            case vsCMAccess.vsCMAccessProject:
                                return StandardGlyphGroup.GlyphExtensionMethodInternal;
                            case vsCMAccess.vsCMAccessProjectOrProtected:
                                return StandardGlyphGroup.GlyphExtensionMethodInternal;
                            case vsCMAccess.vsCMAccessProtected:
                                return StandardGlyphGroup.GlyphExtensionMethodProtected;
                            //case vsCMAccess.vsCMAccessPublic:
                            //    break;
                            //case vsCMAccess.vsCMAccessWithEvents:
                            //    break;
                            default:
                                return StandardGlyphGroup.GlyphExtensionMethod;
                        }
                    }
                    return StandardGlyphGroup.GlyphGroupMethod;
                //case vsCMElement.vsCMElementFunctionInvokeStmt:
                //    break;
                case vsCMElement.vsCMElementIDLCoClass:
                    return StandardGlyphGroup.GlyphGroupClass;
                //case vsCMElement.vsCMElementIDLImport:
                //    break;
                //case vsCMElement.vsCMElementIDLImportLib:
                //    break;
                case vsCMElement.vsCMElementIDLLibrary:
                    return StandardGlyphGroup.GlyphReference;//
                //case vsCMElement.vsCMElementImplementsStmt:
                //    break;
                //case vsCMElement.vsCMElementImportStmt:
                //    break;
                //case vsCMElement.vsCMElementIncludeStmt:
                //    break;
                //case vsCMElement.vsCMElementInheritsStmt:
                //    break;
                case vsCMElement.vsCMElementInterface:
                    return StandardGlyphGroup.GlyphGroupInterface;
                //case vsCMElement.vsCMElementLocalDeclStmt:
                //    break;
                case vsCMElement.vsCMElementMacro:
                    return StandardGlyphGroup.GlyphGroupMacro;
                case vsCMElement.vsCMElementMap:
                    return StandardGlyphGroup.GlyphGroupMap;
                case vsCMElement.vsCMElementMapEntry:
                    return StandardGlyphGroup.GlyphGroupMapItem;
                case vsCMElement.vsCMElementModule:
                    return StandardGlyphGroup.GlyphGroupModule;
                case vsCMElement.vsCMElementNamespace:
                    return StandardGlyphGroup.GlyphGroupNamespace;
                //case vsCMElement.vsCMElementOptionStmt:
                //    break;
                case vsCMElement.vsCMElementOther:
                    return StandardGlyphGroup.GlyphGroupUnknown;
                //case vsCMElement.vsCMElementParameter:
                //    break;//
                case vsCMElement.vsCMElementProperty:
                    return StandardGlyphGroup.GlyphGroupProperty;
                //case vsCMElement.vsCMElementPropertySetStmt:
                //    break;
                case vsCMElement.vsCMElementStruct:
                    return StandardGlyphGroup.GlyphGroupStruct;
                case vsCMElement.vsCMElementTypeDef:
                    return StandardGlyphGroup.GlyphGroupTypedef;
                //case vsCMElement.vsCMElementUDTDecl:
                //    break;
                //case vsCMElement.vsCMElementUnion:
                //    break;
                //case vsCMElement.vsCMElementUsingStmt:
                //    break;
                //case vsCMElement.vsCMElementVBAttributeGroup:
                //    break;
                //case vsCMElement.vsCMElementVBAttributeStmt:
                //    break;
                //case vsCMElement.vsCMElementVCBase:
                //    break;
                case vsCMElement.vsCMElementVariable:
                    object objectParent = ((CodeVariable)CodeElementInstance).Parent;
                    if (objectParent != null && objectParent is CodeElement && ((CodeElement)objectParent).Kind == vsCMElement.vsCMElementEnum)
                    {
                        return StandardGlyphGroup.GlyphGroupEnumMember;
                    }
                    else if (((CodeVariable)CodeElementInstance).IsConstant)
                    {
                        return StandardGlyphGroup.GlyphGroupConstant;
                    }
                    return StandardGlyphGroup.GlyphGroupField;
                default:
                    return StandardGlyphGroup.GlyphGroupUnknown;
            }
        }

        public static StandardGlyphItem GetGlyphItem(this CodeElement CodeElementInstance)
        {
            switch (CodeElementInstance.GetAccess())
            {
                case vsCMAccess.vsCMAccessAssemblyOrFamily:
                    return StandardGlyphItem.GlyphItemInternal;
                //case vsCMAccess.vsCMAccessDefault:
                //    break;
                case vsCMAccess.vsCMAccessPrivate:
                    return StandardGlyphItem.GlyphItemPrivate;
                case vsCMAccess.vsCMAccessProject:
                    return StandardGlyphItem.GlyphItemInternal;
                //case vsCMAccess.vsCMAccessProjectOrProtected:
                //    return StandardGlyphItem.GlyphItemInternal | StandardGlyphItem.GlyphItemProtected;
                case vsCMAccess.vsCMAccessProtected:
                    return StandardGlyphItem.GlyphItemProtected;
                //case vsCMAccess.vsCMAccessPublic:
                //    return StandardGlyphItem.GlyphItemPublic;
                //case vsCMAccess.vsCMAccessWithEvents:
                //    break;
                default:
                    return StandardGlyphItem.GlyphItemPublic;
            }
        }

        public static ImageSource GetImageSource(this CodeElement CodeElementInstance)
        {
            IGlyphService service = GlyphService.GetService();
            if (service == null)
            {
                return null;
            }
            return service.GetGlyph(CodeElementInstance.GetGlyphGroup(), CodeElementInstance.GetGlyphItem());
        }

        public static bool CanBePartial(this CodeElement CodeElementInstance)
        {
            switch (CodeElementInstance.Kind)
            {
                case vsCMElement.vsCMElementClass:
                case vsCMElement.vsCMElementInterface:
                case vsCMElement.vsCMElementStruct:
                    return true;
                default:
                    return false;
            }
        }

        public static CodeElements GetParts(this CodeElement CodeElementInstance)
        {
            switch (CodeElementInstance.Kind)
            {
                case vsCMElement.vsCMElementClass:
                    return ((CodeClass2)CodeElementInstance).Parts;
                case vsCMElement.vsCMElementInterface:
                    return ((CodeInterface2)CodeElementInstance).Parts;
                case vsCMElement.vsCMElementStruct:
                    return ((CodeStruct2)CodeElementInstance).Parts;
                default:
                    return null;
            }
        }

    }
}
